/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.vojna.ant_alg.algorithms;

import pl.vojna.ant_alg.Algorithm;
import pl.vojna.ant_alg.PbbFunction;
import pl.vojna.ant_alg.Problem;
import pl.vojna.ant_alg.Utils;

/**
 * 
 * @author rusak
 */
public class AntSystem implements Algorithm {

	double heuristicFactor;
	double pheromoneFactor;
	double pheromoneVanish;
	double pheromoneStrength;

	public AntSystem(double heuristicFactor, double pheromoneFactor,
			double pheromoneVanish, double pheromoneStrength) {
		this.heuristicFactor = heuristicFactor;
		this.pheromoneFactor = pheromoneFactor;
		this.pheromoneVanish = pheromoneVanish;
		this.pheromoneStrength = pheromoneStrength;
	}

	protected Ant[] results(Problem problem, int popSize, Boolean isDebug,
			final double pheromoneTrails[][]) {
		int antSize = problem.getSize();
		final double heuristicInfo[][] = Utils.heuristicInfo(problem);
		// final double pheromoneTrails[][] = new double[antSize][antSize];
		// initPhereomone(pheromoneTrails, antSize);
		if (isDebug) {
			System.out.println("HEURISTIC INFO: "
					+ Utils.showArray(heuristicInfo));
		}

		Ant population[] = new Ant[popSize];

		for (int i = 0; i < popSize; i++) {
			population[i] = new Ant(antSize, problem, new PbbFunction() {
				@Override
				public double call(int i, int j) {
					return Math.pow(pheromoneTrails[i][j], pheromoneFactor)
							* Math.pow(heuristicInfo[i][j], heuristicFactor);
				}
			});
		}

		int assignedInThisStep[][] = new int[popSize][2];

		for (int i = 0; i < antSize; i++) {
			if (isDebug) {
				System.out.println("STEP: " + i);
			}

			
			if (isDebug) {
				System.out.print("PHEROMONE TRAILS: "
						+ Utils.showArray(pheromoneTrails));
			}
			for (int j = 0; j < popSize; j++) {
				assignedInThisStep[j] = population[j].nextStep(pheromoneTrails);
				if (isDebug) {
					System.out.println("ANT " + j + ":");
					Utils.showSolution(population[j].getSolution());
				}
			}

			/*for (int j = 0; j < popSize; j++) {
				pheromoneTrails[assignedInThisStep[j][0]][assignedInThisStep[j][1]] += (pheromoneStrength / population[j]
						.getCost());
			}*/
		}
                int[] antSol;
                for (int j = 0; j < popSize; j++) {
                    antSol = population[j].getSolution();
                    for(int z = 0;z<antSize;z++) {
                    pheromoneTrails[z][antSol[z]] += (pheromoneStrength/population[j].getCost()); 
                            }
                }
		return population;

	}

	protected double[][] initPhereomone(int problemSize) {
		final double pheromoneTrails[][] = new double[problemSize][problemSize];
		for (int i = 0; i < problemSize; i++) {
			for (int j = 0; j < problemSize; j++) {
				pheromoneTrails[i][j] = 1;
			}
		}
		return pheromoneTrails;
	}

	@Override
	public int[] solve(Problem problem, int popSize, Boolean isDebug,
			int noIterations) {
		int antSize = problem.getSize();
		final double pheromoneTrails[][] = initPhereomone(antSize);

		int best[] = null;
		for (int k = 0; k < noIterations; k++) {
			Ant[] population = results(problem, popSize, isDebug,
					pheromoneTrails);
			if (k == 0) {
				best = population[0].getSolution();
			}

			double bestCost = Utils.solutionCost(problem, best);
			int pretender[];
			double pretenderCost;
			for (int i = 1; i < popSize; i++) {
				pretender = population[i].getSolution();
				pretenderCost = population[i].getCost();
				if (pretenderCost < bestCost) {
					best = pretender;
					bestCost = pretenderCost;
				}
			}
                        vanishPheromone(pheromoneTrails);
		}

		return best;
	}

	private void vanishPheromone(double pheromoneTrails[][]) {
		int size = pheromoneTrails.length;
		for (int i = 0; i < size; i++) {
			for (int j = 0; j < size; j++) {
				pheromoneTrails[i][j] *= (1 - pheromoneVanish);
			}
		}

	}
}
